---
title: Combining Provider States
---

import charactersProvider from "/docs/concepts/combining_provider_states/characters_provider";
import cityProvider from "/docs/concepts/combining_provider_states/city_provider";
import filteredTodoListProvider from "/docs/concepts/combining_provider_states/filtered_todo_list_provider";
import readInProvider from "/docs/concepts/combining_provider_states/read_in_provider";
import selectAsyncProvider from "/docs/concepts/combining_provider_states/select_async_provider";
import todoListProvider from "/docs/concepts/combining_provider_states/todo_list_provider";
import weatherProvider from "/docs/concepts/combining_provider_states/weather_provider";
import wholeObjectProvider from "/docs/concepts/combining_provider_states/whole_object_provider";
import { Link } from "@site/src/components/Link";
import {
  trimSnippet,
  AutoSnippet,
  When,
} from "@site/src/components/CodeSnippet";

:::caution
<!---
The content of this page may be outdated.  
It will be updated in the future, but for now you may want to refer to the content
in the top of the sidebar instead (introduction/essentials/case-studies/...)
-->
本页内容可能已经过时。  
今后会进行更新，但目前您可能需要参考侧边栏顶部的内容（介绍/要点/应用案例/......）。
:::

Make sure to read <Link documentID="concepts2/providers"/> first.  
In this guide, we will learn about combining provider states.

## Combining provider states

We've previously seen how to create a simple provider. But the reality is,
in many situations a provider will want to read the state of another provider.

To do that, we can use the [ref] object passed to the callback of our provider,
and use its [watch] method.

As an example, consider the following provider:

<AutoSnippet language="dart" {...cityProvider}></AutoSnippet>

We can now create another provider that will consume our `cityProvider`:

<AutoSnippet language="dart" {...weatherProvider}></AutoSnippet>

That's it. We've created a provider that depends on another provider.

## FAQ

### What if the value being listened to changes over time?

Depending on the provider that you are listening to, the value obtained may
change over time.
For example, you may be listening to a [NotifierProvider], or the provider
being listened to may have been forced to refresh through the use of
[ProviderContainer.refresh]/[ref.refresh].

When using [watch], Riverpod is able to detect that the value being listened to changed
and will _automatically_ re-execute the provider's creation callback when needed.

This can be useful for computed states.
For example, consider a <Link documentID="providers/notifier_provider"/> that exposes a todo-list:

<AutoSnippet language="dart" {...todoListProvider}></AutoSnippet>

A common use-case would be to have the UI filter the list of todos to show
only the completed/uncompleted todos.

An easy way to implement such a scenario would be to:

- create a [StateProvider], which exposes the currently selected filter method:

  ```dart
  enum Filter {
    none,
    completed,
    uncompleted,
  }

  final filterProvider = StateProvider((ref) => Filter.none);
  ```

- make a separate provider which combines the filter method and the todo-list
  to expose the filtered todo-list:

  <AutoSnippet language="dart" {...filteredTodoListProvider}></AutoSnippet>

Then, our UI can listen to `filteredTodoListProvider` to listen to the filtered todo-list.  
Using such an approach, the UI will automatically update when either the filter
or the todo-list changes.

To see this approach in action, you can look at the source code of the [Todo List
example](https://github.com/rrousselGit/riverpod/tree/master/examples/todos).

:::info
This behavior is not specific to [Provider], and works with all providers.

For example, you could combine [watch] with [FutureProvider] to implement a search
feature that supports live-configuration changes:

<AutoSnippet language="dart" {...charactersProvider}></AutoSnippet>

This code will fetch a list of characters from the service, and automatically
re-fetch the list whenever the configurations change or when the search query changes.
:::

### Can I read a provider without listening to it?

Sometimes, we want to read the content of a provider, but without re-creating
the value exposed when the value obtained changes.

An example would be a `Repository`, which reads from another provider the user token
for authentication.  
We could use [watch] and create a new `Repository` whenever the user token changes,
but there is little to no use in doing that.

In this situation, we can use [read], which is similar to [watch], but will not
cause the provider to recreate the value it exposes when the value obtained changes.

In that case, a common practice is to pass the provider's `Ref` to the object created.
The object created will then be able to read providers whenever it wants.

```dart
final userTokenProvider = StateProvider<String>((ref) => null);

final repositoryProvider = Provider(Repository.new);

class Repository {
  Repository(this.ref);

  final Ref ref;

  Future<Catalog> fetchCatalog() async {
    String token = ref.read(userTokenProvider);

    final response = await dio.get('/path', queryParameters: {
      'token': token,
    });

    return Catalog.fromJson(response.data);
  }
}
```

:::danger **DON'T** call [read] inside the body of a provider

<AutoSnippet language="dart" {...readInProvider}></AutoSnippet>

If you used [read] as an attempt to avoid unwanted rebuilds of your object,
refer to [My provider updates too often, what can I do?](#my-provider-updates-too-often-what-can-i-do)
:::

### How to test an object that receives [ref] as a parameter of its constructor?

If you are using the pattern described in [Can I read a provider without listening to it?](#can-i-read-a-provider-without-listening-to-it),
you may be wondering how to write tests for your object.

In this scenario, consider testing the provider directly instead of the raw object.
You can do so by using the [ProviderContainer] class:

```dart
final repositoryProvider = Provider((ref) => Repository(ref));

test('fetches catalog', () async {
  final container = ProviderContainer();
  addTearDown(container.dispose);

  Repository repository = container.read(repositoryProvider);

  await expectLater(
    repository.fetchCatalog(),
    completion(Catalog()),
  );
});
```

### My provider updates too often, what can I do?

If your object is re-created too often your provider is likely listening
to objects that it doesn't care about.

For example, you may be listening to a `Configuration` object, but only use the `host`
property.  
By listening to the entire `Configuration` object, if a property other than `host`
changes, this still causes your provider to be re-evaluated – which may be
undesired.

The solution to this problem is to create a separate provider that exposes _only_
what you need in `Configuration` (so `host`):

**AVOID** listening to the entire object:

<AutoSnippet language="dart" {...wholeObjectProvider}></AutoSnippet>

**PREFER** using select when you only need a single property of an object:

<AutoSnippet language="dart" {...selectAsyncProvider}></AutoSnippet>

This will only rebuild the `productsProvider` when the `host` changes.

[provider]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/Provider-class.html
[stateprovider]: https://pub.dev/documentation/hooks_riverpod/latest/legacy/StateProvider-class.html
[futureprovider]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/FutureProvider-class.html
[statenotifierprovider]: https://pub.dev/documentation/hooks_riverpod/latest/legacy/StateNotifierProvider-class.html
[notifierProvider]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/NotifierProvider-class.html
[ref]: https://pub.dev/documentation/riverpod/latest/riverpod/Ref-class.html
[watch]: https://pub.dev/documentation/riverpod/latest/riverpod/Ref/watch.html
[read]: https://pub.dev/documentation/riverpod/latest/riverpod/Ref/read.html
[providercontainer.refresh]: https://pub.dev/documentation/riverpod/latest/riverpod/ProviderContainer/refresh.html
[ref.refresh]: https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/WidgetRef/refresh.html
[providercontainer]: https://pub.dev/documentation/riverpod/latest/riverpod/ProviderContainer-class.html
